﻿using HuaCheng.Controller;
using HuaCheng.DataAccess;
using HuaCheng.Model;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using System.Data;
using HuaCheng.Views;
using HuaCheng.CommonClass;
using System.Collections.Concurrent;
using System.Text;

namespace HuaCheng.SendAndReceive
{
    public class StepRun
    {
        public int showViewCount = 0;
        //用来表示当前通道运行产生的记录条数
        private int currentRecordCount = 0;
        //独立模式参数包
        CommandProtocol.IndependParameter inPara = new CommandProtocol.IndependParameter();
        //并联模式参数包
        CommandProtocol.ParalleParameter paPara = new CommandProtocol.ParalleParameter();
        //独立模式动作包
        CommandProtocol.IndependAction inAction = new CommandProtocol.IndependAction();
        //并联模式动作包
        CommandProtocol.ParalleAction paAction = new CommandProtocol.ParalleAction();
        //并联模式使能包
        CommandProtocol.ParallePulseEner paPulse = new CommandProtocol.ParallePulseEner();
        //独立模式工况包
        CommandProtocol.IndependWorkCondition inCondition = new CommandProtocol.IndependWorkCondition();
        //并联模式工况包
        CommandProtocol.ParalleWorkCondition paCondition = new CommandProtocol.ParalleWorkCondition();
        //接收Socket信息
        public Socket client;
        //发送用的字节数组
        public byte[] temp;
        //通道状态
        public ChannelState cs = new ChannelState();
        //通道启动基准时间，以后的时间依次加10毫秒
        public DateTime benchMarkTime;
        //标记是否是启动后收到的第一个包,初始值为true
        public bool isFirstProcess = true;
        //包序每65535为一个轮回，用countSeqLoop记录轮回的个数
        public int countSeqLoop = 0;
        //工步启动时间   
        public DateTime beginTime;
        //轮询收到工况请求包开始时间
        public DateTime beginWaitReq;
        //接收数据包时间
        public DateTime nowTime;
        //当前工步已执行时间
        public TimeSpan executionTime;
        //接续时间
        public DateTime contiTime;
        //持续时间开始计算的时间点
        public DateTime durationBeginTime;
        //各个状态位
        public StepRunBool runState = new StepRunBool();
        //工步数据
        public StepSetInfo stepSetInfo;
        //工步号
        public int stepNum = 1;
        //通道的运行状态
        public int worktype = 100;
        //存储循环所在的工步号与循环次数
        public List<int> circList = new List<int>();
        public Dictionary<int, int> circDic = new Dictionary<int, int>();
        //汇总数据的通道号
        public string paStr = "";
        //当前工步状态
        string currentState = "";
        //存储当日数据的数据表名
        public string tableName;
        //存储用于通道显示的数据
        public Channel chl;
        //一秒发送一次数据用的定时器
        public System.Timers.Timer timerShow;
        //100ms发送一次数据用的定时器
        public System.Timers.Timer timerChartShow;
        //每10秒将队列中的数据存储到数据库中的定时器
        public System.Timers.Timer timerInsertData;
        //记录前一工步类型
        public int preStepType;
        //记录前一次记录的状态
        public RecordState recState = new RecordState();
        //保护条件中的时间间隔
        public float timeInterval;
        //保护条件中的电压间隔
        public float volInterval;
        //保护条件中的电流间隔
        public float currInterval;
        //所以工步的跳转条件
        Dictionary<int, List<JumpCondition>> allJcDic = new Dictionary<int, List<JumpCondition>>();
        //所有工步的记录条件
        Dictionary<int, List<RecordCondition>> allRecDic = new Dictionary<int, List<RecordCondition>>();
        //等待接收工况请求的定时器
        public System.Timers.Timer timerRecReq;
        //记录下发工况数据的次数
        int count = 0;
        //工况信息表
        DataTable dt = new DataTable();
        //待插入数据库的通道状态数据队列
        ConcurrentQueue<ChannelData> queData = new ConcurrentQueue<ChannelData>();
        //待插入数据库的跳转日志队列
        Queue<JumpReasonRecord> queJump = new Queue<JumpReasonRecord>();
        //用于给批量插入数据库加锁
        private static object insertObj = new object();
        //用于showView加锁
        private static object showViewObj = new object();
        //用于savaData加锁
        private static object savaDataObj = new object();
        //用于实现队列锁的对象
        object synObj = new object();
        //用于实现判断过程加锁的对象
        object synJudgeObj = new object();
        //定义改变通道颜色的委托和事件        
        public delegate void ChangeColor(string c, int r, Channel ch);
        public event ChangeColor ColorChange;
        //定义通道传参的委托和事件
        public delegate void SendParams(string curStat, Channel chl, int r);
        public event SendParams ParamsTransport;
        //定义动态曲线通道传参的委托和事件
        public delegate void SendChartParams(string curStat, Channel chl, int r);
        public event SendChartParams ParamsChartTransport;
        //定义迁移的委托和事件
        public delegate void MoveStep(int realId);
        public event MoveStep StartMove;
        //关机校验的事件和委托
        public delegate void CloseJudge(string ip, int cid, int stepNum, int gid, CommandProtocol.IndependAction inAction, CommandProtocol.ParalleAction paAction, bool isParalle);
        public event CloseJudge ChannelCloseJudge;
        //是否记录跳转条件
        public string RecordJump;
        //记录当前处理包的包序
        public int currSeq;
        //记录暂停时的包序
        public int pauseSeq;
        //记录接续时的包序
        public int continueSeq;
        //Channelstate队列
        public ConcurrentQueue<ChannelState> queCS = new ConcurrentQueue<ChannelState>();
        //ChannelStateList队列
        public ConcurrentQueue<List<ChannelState>> queCList = new ConcurrentQueue<List<ChannelState>>();
        //用来标志showView线程是否执行完毕
        public bool isShowViewThreadOver = true;
        //用来标志savaData线程是否执行完毕
        public bool isSavaDataThreadOver = true;
        public StepRun(Socket clientsocket)
        {
            client = clientsocket;
            runState.isMoveStep = false;//默认不是迁移操作
        }
        #region 委托事件
        /// <summary>
        /// 关机委托
        /// </summary>
        /// <param name="i"></param>
        public void OnCloseJudge(string ip, int cid, int stepNum, int gid, CommandProtocol.IndependAction inAction, CommandProtocol.ParalleAction paAction, bool isParalle)
        {
            if (ChannelCloseJudge != null)
            {
                ChannelCloseJudge(ip, cid, stepNum, gid, inAction, paAction, isParalle);
            }
        }
        /// <summary>
        /// 改变颜色
        /// </summary>
        /// <param name="c"></param>
        /// <param name="r"></param>
        public void OnColorChange(string c, int r, Channel ch)
        {
            if (ColorChange != null)
            {
                ColorChange(c, r, ch);
            }
        }
        /// <summary>
        /// 发送1s数据到IndexPage
        /// </summary>
        /// <param name="curStat"></param>
        /// <param name="chl"></param>
        /// <param name="r"></param>
        public void OnSendParams(string curStat, Channel chl, int r)
        {
            if (ParamsTransport != null)
            {
                ParamsTransport(curStat, chl, r);
            }
        }
        /// <summary>
        /// 发送100ms数据到IndexPage
        /// </summary>
        /// <param name="curStat"></param>
        /// <param name="chl"></param>
        /// <param name="r"></param>
        public void OnSendChartParams(string curStat, Channel chl, int r)
        {
            if (ParamsChartTransport != null)
            {
                ParamsChartTransport(curStat, chl, r);
            }
        }
        /// <summary>
        /// 开始执行迁移操作
        /// </summary>
        public void OnStartMove(int realId)
        {
            if (StartMove != null)
            {
                StartMove(realId);
            }
        }
        #endregion
        #region 接收客户端数据--前期准备
        /// <summary>
        /// 接收客户端数据--前期准备
        /// </summary>
        /// <param name="state"></param>
        public void Receive(object state)
        {
            stepSetInfo = (StepSetInfo)state;
            if (client != null)
            {
                //工步运行前开机，启动等指令的下发
                PrepareReceive(stepSetInfo);
                //开机校验通过
                if (runState.isOn)
                {
                    ////1s传送通道显示用数据的定时器
                    timerShow = new System.Timers.Timer(10);
                    //定时器达到时间间隔后，执行的方法
                    timerShow.Elapsed += (s, ela) =>
                    {
                        runState.needShow = true;
                    };
                    timerShow.AutoReset = true;
                    timerShow.Enabled = true;
                    timerShow.Start();
                    ////1000ms传送通道显示用数据的定时器
                    //timerChartShow = new System.Timers.Timer(1000);
                    //timerChartShow.Elapsed += (s, ela) =>
                    //{
                    //    runState.chartNeedShow = true;
                    //};
                    //timerChartShow.AutoReset = true;
                    //timerChartShow.Enabled = true;
                    //timerChartShow.Start();

                    //每隔30s将队列中数据存储到数据库的定时器
                    timerInsertData = new System.Timers.Timer(30000);
                    //定时器达到时间间隔后，执行的方法
                    timerInsertData.Elapsed += (s, ela) =>
                    {
                        InsertChannelData();
                    };
                    timerInsertData.AutoReset = true;
                    timerInsertData.Enabled = true;
                    timerInsertData.Start();

                    //获取保护条件中的记录条件
                    //时间间隔，电压间隔，电流间隔
                    timeInterval = Convert.ToSingle(stepSetInfo.StepList[stepNum - 1].ProtCondition.TimeSpan) * 1000;
                    volInterval = Convert.ToSingle(stepSetInfo.StepList[stepNum - 1].ProtCondition.VoltageSpan);
                    currInterval = Convert.ToSingle(stepSetInfo.StepList[stepNum - 1].ProtCondition.CurrentSpan);
                    if (timeInterval == 0 && volInterval == 0 && currInterval == 0)
                    {
                        timeInterval = 100;
                    }

                    //监听IndexPage页面用户的单点暂停，接续动作
                    IndexPage.StopByUser += new IndexPage.UserStop(Pause);
                    //监听IndexPage页面用户的关机菜单点击动作
                    IndexPage.CloseByUser += new IndexPage.UserClose(UserClosing);
                    //监听IndexPage页面用户的跳转菜单点击动作
                    IndexPage.JumpByUser += new IndexPage.UserJump(UserJumping);
                    //监听IndexPage页面用户的重置工步动作
                    IndexPage.NewStep += new IndexPage.StepUpdate(UpdateStep);
                    //监听tcpcontrol的故障处理的方法
                    TcpControl.ChannelErrorCloseJudge += new TcpControl.ErrorCloseJudge(ErrorOccurs);

                    //监听StartListen中的关机方法
                    StartListen.CloseByUser += new StartListen.UserClose(UserClosing);
                    StartListen.NetDisConnect += new StartListen.NetClose(NetClosing);


                    //如果是迁移工步启动的线程，则触发迁移事件
                    if (runState.isMoveStep)
                        OnStartMove(stepSetInfo.RealId);
                    //得到通道的初始电压，初始电流
                    recState = new RecordState();
                    //更新第一工步的启动时间
                    beginTime = DateTime.Now;
                    //先加一层判断，以免此时通道已经关机却又重新运行
                    if (!(runState.isOver || runState.isClosed))
                    {
                        //工步开始运行
                        runState.isRunning = true;
                        //启动待存数据队列的监听
                        //ThreadPool.QueueUserWorkItem(new WaitCallback(InsertChannelData));
                        //得到通道的初始电压，初始电流,插入第一条记录                  
                        if (cs != null)
                        {
                            recState.oldV = cs.DC_outputVolt;
                            recState.oldA = cs.DC_loadCurrent;
                            recState.count = -1;
                            recState.beginSeq = currSeq + 1;
                            recState.needInsert = true;
                        }
                        //等待100ms后，启动指令撤回
                        Thread.Sleep(100);
                        if (!runState.isParalle)
                        {
                            //给发送队列放置一个数据包，下发独立启动撤回指令
                            inAction = StepRunControl.IndependentStartBack(inAction, temp, client);
                        }
                        else
                        {
                            paAction = StepRunControl.ParalleStartBack(paAction, temp, client);
                        }

                        //针对第一个工步是工况的处理
                        if (stepSetInfo.StepList[stepNum - 1].StepName == "斜坡工况" || stepSetInfo.StepList[stepNum - 1].StepName == "脉冲工况")
                        {
                            //发送后续的工况数据
                            SendConditionOverJudge();

                            if (runState.isConditionIfJump)
                            {
                                runState.isConditionIfJump = false;
                            }
                            else
                            {
                                beginTime = default(DateTime);
                                if (runState.isConditionTimeOut)
                                {
                                    runState.isConditionTimeOut = false;
                                }
                                else
                                {
                                    if (RecordJump == "1")
                                    {
                                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                            stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "工况工步数据处理完毕", "跳转到" + stepSetInfo.StepList[stepNum].StepName + "工步");
                                        queJump.Enqueue(jumpReason);
                                    }
                                    //JumpReasonRecordControl.InsertNewJumpReason(jumpReason);
                                }
                                stepNum++;
                                CommandData(stepNum - 1);
                            }
                        }
                    }
                }
                else
                {
                    //记录跳转原因
                    if (RecordJump == "1")
                    {
                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "开机失败", "跳转到完成状态");
                        queJump.Enqueue(jumpReason);
                        JumpReasonRecordControl.InsertNewJumpReason(jumpReason);
                    }
                    //更新通道颜色
                    runState.isChanged = true;
                    runState.needShow = true;
                    currentState = "结束";
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ShowView));
                }
            }
        }
        /// <summary>
        /// 开机校验，工步运行时的操作
        /// </summary>
        /// <param name="bytes"></param>
        public void ProcessData(byte[] bytes, string ip)
        {
            if (ip == stepSetInfo.DevIp)
            {
                //解析包序
                currSeq = BitConverter.ToUInt16(bytes, 718);
                //Console.WriteLine(ip + "processData时的包序:" + currSeq);
                //解析辅助通道数据
                List<AuxChannel> aux = stepSetInfo.ChlList[stepSetInfo.Cid - 1].auxChannel;
                for (int i = 0; i < aux.Count; i++)
                {
                    aux[i] = ChannelStateControl.GetAuxChannelData(bytes, aux[i]);
                }
                //合闸计数
                int count = 0;
                List<ChannelState> csList = new List<ChannelState>();
                ChannelState newcs = new ChannelState();
                try
                {
                    nowTime = DateTime.Now;
                    //如果是第一次处理的包，则记录下此时的系统时间作为基准时间
                    if (isFirstProcess)
                    {
                        benchMarkTime = nowTime;
                        isFirstProcess = false;
                    }
                    //如果不是第一次处理，则将基准时间依次加10赋予给当前时间，并更新基准时间
                    else
                    {
                        benchMarkTime = benchMarkTime.AddMilliseconds(10);
                    }
                    if (!runState.isParalle)
                    {
                        cs = ChannelStateControl.byte2Channel(bytes, stepSetInfo.Cid - 1, 76);
                        cs.IP = stepSetInfo.DevIp;
                        cs.CID = stepSetInfo.Cid - 1;
                        cs.CurrentSeq = currSeq;//包序
                        cs.BeginSeq = recState.beginSeq;//当前工步起始包序
                        cs.PauseSeq = pauseSeq;//当前工步暂停包序
                        cs.ContinueSeq = continueSeq;//当前工步接续包序
                        cs.CurrStepNum = stepNum;//当前工步的工步号
                        cs.BeginTime = beginTime;//当前工步起始时间
                        cs.ContiTime = contiTime;//当前工步接续时间
                        cs.NowTime = nowTime;//当前包被处理的时间
                        cs.ExecutionTime = executionTime;//当前工步已经被执行的时间
                        //接收数据，记录时间                        
                        cs.time = benchMarkTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                        newcs = ChannelStateControl.byte2Channel(bytes, stepSetInfo.Cid - 1, 76);
                        newcs.IP = stepSetInfo.DevIp;
                        newcs.CID = stepSetInfo.Cid - 1;
                        newcs.CurrentSeq = currSeq;//包序
                        newcs.BeginSeq = recState.beginSeq;//当前工步起始包序
                        newcs.PauseSeq = pauseSeq;//当前工步暂停包序
                        newcs.ContinueSeq = continueSeq;//当前工步接续包序
                        newcs.CurrStepNum = stepNum;//当前工步的工步号
                        newcs.BeginTime = beginTime;//当前工步起始时间
                        newcs.ContiTime = contiTime;//当前工步接续时间
                        newcs.NowTime = nowTime;//当前包被处理的时间
                        newcs.ExecutionTime = executionTime;//当前工步已经被执行的时间
                        //接收数据，记录时间                        
                        newcs.time = benchMarkTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                        //newcs = CloneModel<ChannelState>(cs);
                        if (runState.isRunning || runState.isClosed == true)
                        {
                            queCS.Enqueue(newcs);
                        }
                        csList.Add(newcs);
                        if (cs.DCstate2_Contactor == true)
                        {
                            count++;
                        }
                    }
                    else
                    {
                        cs = ChannelStateControl.byte2Channel(bytes, stepSetInfo.Cid - 1, 76);
                        cs.IP = stepSetInfo.DevIp;
                        cs.CID = stepSetInfo.Cid - 1;
                        cs.CurrentSeq = currSeq; //包序
                        cs.BeginSeq = recState.beginSeq;//当前工步起始包序
                        cs.PauseSeq = pauseSeq;//当前工步暂停包序
                        cs.ContinueSeq = continueSeq;//当前工步接续包序
                        cs.CurrStepNum = stepNum;//当前工步的工步号
                        cs.BeginTime = beginTime;//当前工步起始时间
                        cs.ContiTime = contiTime;//当前工步接续时间
                        cs.NowTime = nowTime;//当前包被处理的时间
                        cs.ExecutionTime = executionTime;//当前工步已经被执行的时间
                        cs.time = benchMarkTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                        newcs = ChannelStateControl.byte2Channel(bytes, stepSetInfo.Cid - 1, 76);
                        newcs.IP = stepSetInfo.DevIp;
                        newcs.CID = stepSetInfo.Cid - 1;
                        newcs.CurrentSeq = currSeq;//包序
                        newcs.BeginSeq = recState.beginSeq;//当前工步起始包序
                        newcs.PauseSeq = pauseSeq;//当前工步暂停包序
                        newcs.ContinueSeq = continueSeq;//当前工步接续包序
                        newcs.CurrStepNum = stepNum;//当前工步的工步号
                        newcs.BeginTime = beginTime;//当前工步起始时间
                        newcs.ContiTime = contiTime;//当前工步接续时间
                        newcs.NowTime = nowTime;//当前包被处理的时间
                        newcs.ExecutionTime = executionTime;//当前工步已经被执行的时间
                        //接收数据，记录时间                        
                        newcs.time = benchMarkTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                        //cs.time = nowTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                        //并联模式，解析所有并联组中的通道数据
                        for (int i = 0; i < stepSetInfo.ParallelList.Count; i++)
                        {
                            ChannelState paChlState = ChannelStateControl.byte2Channel(bytes, stepSetInfo.ParallelList[i] - 1, 76);
                            paChlState.CurrentSeq = currSeq; //包序
                            paChlState.BeginSeq = recState.beginSeq;//当前工步起始包序
                            paChlState.PauseSeq = pauseSeq;//当前工步暂停包序
                            paChlState.ContinueSeq = continueSeq;//当前工步接续包序
                            paChlState.CurrStepNum = stepNum;//当前工步的工步号
                            paChlState.BeginTime = beginTime;//当前工步起始时间
                            paChlState.ContiTime = contiTime;//当前工步接续时间
                            paChlState.NowTime = nowTime;//当前包被处理的时间
                            paChlState.ExecutionTime = executionTime;//当前工步已经被执行的时间
                            paChlState.time = benchMarkTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                            //将并联的几个通道的数据分别加入list
                            csList.Add(paChlState);
                            if (paChlState.DCstate2_Contactor == true)
                            {
                                count++;
                            }
                            if (i != 0)
                            {
                                cs.DC_loadCurrent = cs.DC_loadCurrent + paChlState.DC_loadCurrent;
                                cs.totalCap = cs.totalCap + paChlState.totalCap;
                                cs.totalEnergy = cs.totalEnergy + paChlState.totalEnergy;
                                cs.chargeCap = cs.chargeCap + paChlState.chargeCap;
                                cs.chargeEnergy = cs.chargeEnergy + paChlState.chargeEnergy;
                                cs.dischargeCap = cs.dischargeCap + paChlState.dischargeCap;
                                cs.dischargeEnergy = cs.dischargeEnergy + paChlState.dischargeEnergy;
                                cs.power = cs.power + paChlState.power;
                                cs.faultStatus = "";
                                newcs.DC_loadCurrent = newcs.DC_loadCurrent + paChlState.DC_loadCurrent;
                                newcs.totalCap = newcs.totalCap + paChlState.totalCap;
                                newcs.totalEnergy = newcs.totalEnergy + paChlState.totalEnergy;
                                newcs.chargeCap = newcs.chargeCap + paChlState.chargeCap;
                                newcs.chargeEnergy = newcs.chargeEnergy + paChlState.chargeEnergy;
                                newcs.dischargeCap = newcs.dischargeCap + paChlState.dischargeCap;
                                newcs.dischargeEnergy = newcs.dischargeEnergy + paChlState.dischargeEnergy;
                                newcs.power = newcs.power + paChlState.power;
                                newcs.faultStatus = "";
                            }
                        }
                        //将汇总数据加入list
                        //newcs = CloneModel<ChannelState>(cs);
                        if (runState.isRunning || runState.isClosed == true)
                        {
                            queCS.Enqueue(newcs);
                        }
                        csList.Add(newcs);
                    }
                    //通道还在运行中的时候才入队
                    if (runState.isRunning || runState.isClosed == true)
                    {
                        queCList.Enqueue(csList);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.StackTrace + e.Message);
                }
                //开机校验
                if (runState.isOpenJudge)
                {
                    int mapCount = ChannelMapControl.GetDevChlMapLine(ip, stepSetInfo.Gid, stepSetInfo.Mid);//读取每行排列个数
                    //int realId = (stepSetInfo.Mid-1) * mapCount + stepSetInfo.Cid-1;
                    int realId = stepSetInfo.RealId;
                    if (IndexPage.allDevChl[ip][realId].ChlStepName != "故障")
                    {
                        runState = StepRunControl.OpenJudge(beginTime, runState, count, stepSetInfo.ParallelList.Count);
                        if ((!runState.isOn) && (!runState.isOpenJudge))//若未开机成功则提示开机合闸失败
                        {
                            ThreadPool.QueueUserWorkItem(new WaitCallback(StepRunControl.OpenShowMsg), stepSetInfo);
                        }
                    }
                    else
                    {
                        if ((!runState.isOn) && (!runState.isOpenJudge))//若未开机成功则提示开机合闸失败
                        {
                            ThreadPool.QueueUserWorkItem(new WaitCallback(StepRunControl.OpenErrorShowMsg), stepSetInfo);
                        }
                        runState.isOn = false;
                        runState.isOpenJudge = false;
                    }
                }
                //工步执行
                else
                {
                    if (runState.isRunning)
                    {
                        //开启三个线程
                        //ThreadPool.SetMaxThreads(1000, 1000);
                        //ThreadPool.SetMinThreads(10, 10);
                        ThreadPool.QueueUserWorkItem(new WaitCallback(SaveData));//插入队列线程
                        ThreadPool.QueueUserWorkItem(new WaitCallback(StepJudge), stepSetInfo.StepList);//开启工步切换判断线程
                        //showViewCount++;
                        //if (showViewCount == 100)
                        //{
                        ThreadPool.QueueUserWorkItem(new WaitCallback(ShowViewRunning));//通道界面显示
                        //showViewCount = 0;
                        //}                     
                    }
                    else
                    {
                        if (runState.isClosed)
                        {
                            ////接收数据，记录时间
                            //nowTime = DateTime.Now;
                            //cs.time = nowTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
                            //cs.IP = stepSetInfo.DevIp;
                            //cs.CID = stepSetInfo.Cid - 1;
                            //cs.CurrentSeq = currSeq;
                            //关机后只有存储数据线程会再跑5s
                            ThreadPool.QueueUserWorkItem(new WaitCallback(SaveData));
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 判断是否接受到工况请求并且数据包发送完毕
        /// </summary>
        /// <param name="bytes"></param>
        public void ProcessCondiReq(CondiRequest condiReq, string ip)
        {
            if (ip == stepSetInfo.DevIp)
            {
                //if (stepSetInfo.Mid - 1 == condiReq.GID && stepSetInfo.Cid - 1 == condiReq.CID)
                if (stepSetInfo.Cid - 1 == condiReq.CID)
                {
                    //如果正在等待工况请求
                    if (runState.isReceiveJudge)
                    {
                        int paraCount = stepSetInfo.ParallelList.Count;
                        if (count == 1)//发送完第一条数据做收到工况请求判断
                        {
                            //表示接收到了工况请求
                            runState.receiveConReq = true;
                            //判断是否超时
                            runState = StepRunControl.SendNextConditionData(count, dt, beginWaitReq, runState, temp, inCondition, paCondition, client, paraCount);
                            timerRecReq.Close();
                            runState.isReceiveJudge = false;
                            count++;
                        }
                        else//之后的超时判断
                        {
                            if (runState.hasMoreData)//一直做是否接受到工况请求判断直到数据包发送完毕
                            {
                                runState.receiveConReq = true;
                                runState = StepRunControl.SendNextConditionData(count, dt, beginWaitReq, runState, temp, inCondition, paCondition, client, paraCount);
                                timerRecReq.Close();
                                runState.isReceiveJudge = false;
                                count++;
                                if (runState.hasMoreData)
                                {
                                    runState.receiveConReq = false;
                                    float waitTime = TotalTimeControl.CalTotalTime(count, dt, "时间") * 1000 + 5000;
                                    ReceiveReqStateJudge(waitTime);
                                }
                            }
                            else
                            {
                                timerRecReq.Close();
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #region 工步执行前准备工作
        /// <summary>
        /// 工步执行前的准备工作
        /// </summary>
        /// <param name="sp"></param>
        private void PrepareReceive(StepSetInfo sp)
        {
            //获取是否需要进行跳转原因的配置信息
            RecordJump = DicHelper.RetrieveJumpRecord();

            //在startListen中设置的事件，这里绑定监听
            //startListen中做一次，但是这里有可能有8个绑定了监听
            //1.状态包 2.工况请求包
            StartListen.ReceiveChannelData += new StartListen.ReceiveData(ProcessData);
            StartListen.ReceiveCondiRequest += new StartListen.ReceiveCondiReq(ProcessCondiReq);

            stepNum = sp.StartStep;
            chl = sp.ChlList[sp.RealId];
            //把通道的并联信息转化为01字符串
            if (sp.ParallelList.Count > 0)
            {
                runState.isParalle = true;
                for (int p = 8; p > 0; p--)
                {
                    if (sp.ParallelList.Contains(p))
                    {
                        paStr += "1";
                    }
                    else
                    {
                        paStr += "0";
                    }
                }
            }
            //获取各工步的如果工步和记录条件工步数据
            for (int i = 0; i < sp.StepList.Count; i++)
            {
                //获取工步方案中循环的个数
                if (stepSetInfo.StepList[i].StepName == "循环")
                {
                    circList.Add(i);
                    circDic.Add(i, 0);
                }
                List<JumpCondition> jcList = new List<JumpCondition>();
                List<RecordCondition> recList = new List<RecordCondition>();

                //取出截至电流
                if (stepSetInfo.StepList[i].CutoffCurr != null)
                {
                    jcList = StepRunControl.GetCutOffCurrCondition(Convert.ToSingle(stepSetInfo.StepList[i].CutoffCurr), stepSetInfo, jcList, i);
                }

                //各工步的保护条件也按照如果工步来处理，龙涛说改成中位机来处理
                //jcList = StepRunControl.GetProctCondition(stepSetInfo,jcList,i+1);

                if (stepSetInfo.StepList[i].ChildList != null)
                {
                    //获取当前工步的如果工步和记录条件工步数据
                    for (int j = 0; j < stepSetInfo.StepList[i].ChildList.Count; j++)
                    {
                        if (stepSetInfo.StepList[i].ChildList[j].ChildStepName == "如果")
                        {
                            jcList.Add(StepRunControl.GetStepJumpCondition(stepSetInfo, i, j));
                        }
                        else if (stepSetInfo.StepList[i].ChildList[j].ChildStepName == "记录条件")
                        {
                            recList.Add(StepRunControl.GetStepRecordCondition(stepSetInfo, i, j));
                        }
                    }
                }
                allJcDic.Add(i, jcList);
                allRecDic.Add(i, recList);
            }
            //如果不存在存储当日数据的数据表，则新建数据表
            tableName = ChannelDataHelper.CreateTodayTable(sp.DevIp, sp.Cid);
            //独立模式
            if (!runState.isParalle)
            {
                //设置独立参数包的固定参数
                inPara = StepRunControl.InParaFixedValueSet(sp, inPara);
                //设置独立动作包的固定参数
                inAction = StepRunControl.InActionFixedValueSet(sp, inAction);
                //设置独立工况包的固定参数
                inCondition = StepRunControl.InConditionFixedValueSet(sp, inCondition);
                inPara.stepNum = stepNum - 1;
                inAction.stepNum = stepNum - 1;
                //独立模式的系统复位
                inAction = StepRunControl.IndependentSystemReset(inAction, temp, client);
                //等待100ms后，复位指令撤回
                Thread.Sleep(100);
                //独立模式系统复位撤回
                inAction = StepRunControl.IndependentSystemResetBack(inAction, temp, client);
                //更新通道为开机中状态
                runState.isChanged = true;
                if (!runState.isMoveStep)
                {
                    runState.needShow = true;
                }
                currentState = "开机中";
                ThreadPool.QueueUserWorkItem(new WaitCallback(ShowViewRunning), "开机中");

                //发送第一条参数指令
                CommandData(stepNum - 1);
                //Thread.Sleep(10);
                //判断第一个工步是否为工况工步
                if (sp.StepList[stepNum - 1].StepName == "斜坡工况" || sp.StepList[stepNum - 1].StepName == "脉冲工况")
                {
                    //读取excel工况信息
                    dt = sp.StepList[stepNum - 1].Dt;
                    runState.hasMoreData = true;
                    IndependSendWork(dt, inCondition);//发送前两条工况指令
                    //如果收到了工况包请求
                    if (runState.receiveConReq)
                    {
                        runState.receiveConReq = false;
                        //Thread.Sleep(10);
                        //开机
                        inAction = StepRunControl.IndependentOpen(inAction, temp, client);
                        //监听开机状态
                        OpenStateJudge();
                        //runState.isOn = true;
                        //开机成功
                        if (runState.isOn)
                        {
                            //开机指令撤回
                            inAction = StepRunControl.IndependentOpenBack(inAction, temp, client);
                            //启动指令下达
                            inAction = StepRunControl.IndependentStart(inAction, temp, client);
                        }
                    }
                }
                else//独立非工况模式
                {
                    //开机
                    inAction = StepRunControl.IndependentOpen(inAction, temp, client);
                    //Console.WriteLine("---------通道:" + stepSetInfo.Cid + " 开机中");
                    //监听开机状态
                    OpenStateJudge();
                    //runState.isOn = true;
                    //开机成功
                    if (runState.isOn)
                    {
                        //Console.WriteLine("通道" + stepSetInfo.Cid + "开机校验成功时间" + System.DateTime.Now);
                        //开机指令撤回
                        inAction = StepRunControl.IndependentOpenBack(inAction, temp, client);
                        //启动指令下达
                        inAction = StepRunControl.IndependentStart(inAction, temp, client);
                    }
                }
            }
            //并联模式
            else
            {
                //设置并联参数包的固定参数
                paPara = StepRunControl.PaParaFixedValueSet(sp, paPara);
                //设置并联动作包的固定参数
                paAction = StepRunControl.PaActionFixedValueSet(sp, paAction);
                //设置并联工况包的固定参数
                paCondition = StepRunControl.PaConditionFixedValueSet(sp, paCondition);
                //设置并联使能包的固定参数
                paPulse = StepRunControl.PaPulseFixedValueSet(sp, paPulse);
                paPara.stepNum = stepNum - 1;
                paAction.stepNum = stepNum - 1;
                //设置并联通道组的id
                for (int i = 0; i < sp.ParallelList.Count; i++)
                {
                    paPara.ch[sp.ParallelList[i] - 1] = true;
                    paAction.ch[sp.ParallelList[i] - 1] = true;
                    paPulse.ch[sp.ParallelList[i] - 1] = true;
                    paCondition.ch[sp.ParallelList[i] - 1] = true;
                }
                //并联模式的系统复位
                paAction = StepRunControl.ParalleSystemReset(paAction, temp, client);
                //等待100ms后，复位指令撤回
                Thread.Sleep(100);
                //并联模式的系统复位撤回
                paAction = StepRunControl.ParalleSystemResetBack(paAction, temp, client);
                //更新通道为开机中状态
                runState.isChanged = true;
                runState.needShow = true;
                currentState = "开机中";
                ThreadPool.QueueUserWorkItem(new WaitCallback(ShowViewRunning), "开机中");

                //发送第一条参数指令
                CommandData(stepNum - 1);
                //Thread.Sleep(10);
                //判断第一个工步是否为工况工步
                if (sp.StepList[stepNum - 1].StepName == "斜坡工况" || sp.StepList[stepNum - 1].StepName == "脉冲工况")
                {
                    //读取excel工况信息
                    dt = sp.StepList[stepNum - 1].Dt;
                    runState.hasMoreData = true;
                    ParalleSendWork(dt, paCondition);//发送前两条工况指令
                    //如果收到了工况包请求
                    if (runState.receiveConReq)
                    {
                        runState.receiveConReq = false;
                        //Thread.Sleep(10);
                        //开机
                        paAction = StepRunControl.ParalleOpen(paAction, temp, client);
                        //监听开机状态
                        OpenStateJudge();
                        //runState.isOn = true;
                        //开机成功
                        if (runState.isOn)
                        {
                            //开机指令撤回
                            paAction = StepRunControl.ParalleOpenBack(paAction, temp, client);
                            //Thread.Sleep(10);
                            //并联使能包下发
                            paPulse = StepRunControl.ParallePulse(paPulse, temp, client);
                            //Thread.Sleep(10);
                            //启动指令下达
                            paAction = StepRunControl.ParalleStart(paAction, temp, client);
                        }
                    }
                }
                //并联非工况模式
                else
                {
                    //开机
                    paAction = StepRunControl.ParalleOpen(paAction, temp, client);
                    //监听开机状态
                    OpenStateJudge();
                    //runState.isOn = true;
                    //开机成功
                    if (runState.isOn)
                    {
                        //开机指令撤回
                        paAction = StepRunControl.ParalleOpenBack(paAction, temp, client);
                        //Thread.Sleep(10);
                        //并联使能包下发
                        paPulse = StepRunControl.ParallePulse(paPulse, temp, client);
                        //Thread.Sleep(10);
                        //启动
                        paAction = StepRunControl.ParalleStart(paAction, temp, client);
                    }
                }
            }
        }

        /// <summary>
        /// 开机校验
        /// </summary>
        private void OpenStateJudge()
        {
            //更新开机校验开始时间
            beginTime = System.DateTime.Now;
            //开机校验中
            runState.isOpenJudge = true;
            while (runState.isOpenJudge)
            {
                continue;
            }
        }
        #endregion
        #region 单点暂停与接续,重置工步,故障处理，关机菜单,跳转菜单
        /// <summary>
        /// 单点暂停
        /// </summary>
        /// <param name="isStop"></param>
        public void Pause(bool isStop, int stepNum, TimeSpan executionTime, int realid, string ip, bool isMove)
        {
            //单点暂停
            if (isStop)
            {
                if (realid == this.stepSetInfo.RealId && ip == this.stepSetInfo.DevIp)
                {
                    pauseSeq = currSeq;//暂停时的包序
                    //暂停时插入最后一条记录
                    recState.oldV = cs.DC_outputVolt;
                    recState.oldA = cs.DC_loadCurrent;
                    recState.count = -1;
                    worktype = 102;
                    recState.needInsert = true;
                    //等待插入工作完成
                    while (worktype != 100)
                    {
                        continue;
                    }
                    //停止数据处理
                    runState.isRunning = false;
                    if (!runState.isParalle)
                    {
                        //发送暂停指令
                        inAction.stepNum = stepNum - 1;
                        inAction = StepRunControl.IndependentStop(inAction, temp, client);
                    }
                    else
                    {
                        paAction.stepNum = stepNum - 1;
                        paAction = StepRunControl.ParalleStop(paAction, temp, client);
                    }
                    if (RecordJump == "1")
                    {
                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                            stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "用户点击单点停止", "跳转到暂停状态");
                        queJump.Enqueue(jumpReason);
                    }
                    ////查询当前测试总记录条数
                    //int recordNum = currentRecordCount;
                    ////更新测试表记录条数
                    //TestHelper.UpdateTestRecordNum(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid, recordNum);
                    //关闭层插入数据库的定时器
                    if (timerInsertData != null)
                    {
                        timerInsertData.Close();
                    }
                    InsertChannelData();//将队列中剩余的数据插入到数据库中
                }
            }
            //接续
            else
            {
                if (realid == this.stepSetInfo.RealId && ip == this.stepSetInfo.DevIp)
                {
                    //开启每隔30s将队列中数据存储到数据库的定时器
                    timerInsertData = new System.Timers.Timer(30000);
                    //定时器达到时间间隔后，执行的方法
                    timerInsertData.Elapsed += (s, ela) =>
                    {
                        InsertChannelData();
                    };
                    timerInsertData.AutoReset = true;
                    timerInsertData.Enabled = true;
                    timerInsertData.Start();
                    //继续进行数据处理
                    runState.isRunning = true;
                    //获取暂停时的已执行时间和工步号
                    this.executionTime = executionTime;
                    this.stepNum = stepNum;
                    //记录接续时间，发送启动指令
                    contiTime = DateTime.Now;
                    if (!isMove)
                    {
                        continueSeq = currSeq;
                        //插入接续的第一条记录
                        recState.oldV = cs.DC_outputVolt;
                        recState.oldA = cs.DC_loadCurrent;
                        recState.count = -1;
                        worktype = 103;
                        recState.needInsert = true;
                        //等待插入工作完成
                        while (worktype != 100)
                        {
                            continue;
                        }
                    }
                    ////获取暂停时的已执行时间和工步号
                    //this.executionTime = executionTime;
                    //this.stepNum = stepNum;
                    ////记录接续时间，发送启动指令
                    //contiTime = DateTime.Now;
                    if (!runState.isParalle)
                    {
                        inAction.stepNum = stepNum - 1;
                        inAction = StepRunControl.IndependentStart(inAction, temp, client);
                    }
                    else
                    {
                        paAction.stepNum = stepNum - 1;
                        paAction = StepRunControl.ParalleStart(paAction, temp, client);
                    }
                    //更新通道颜色
                    runState.isChanged = true;
                    runState.needShow = false;
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ShowView));
                    if (!isMove)
                    {
                        if (RecordJump == "1")
                        {
                            string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                            JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "用户点击接续", "继续执行" + stepSetInfo.StepList[stepNum - 1].StepName + "工步");
                            queJump.Enqueue(jumpReason);
                        }
                    }
                    else
                    {
                        if (RecordJump == "1")
                        {
                            string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                            JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "用户点击迁移", "接续迁移前通道继续执行" + stepSetInfo.StepList[stepNum - 1].StepName + "工步");
                            queJump.Enqueue(jumpReason);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 重置工步
        /// </summary>
        /// <param name="sp"></param>
        public void UpdateStep(StepSetInfo sp, int realid, string ip)
        {
            if (realid == this.stepSetInfo.RealId && ip == this.stepSetInfo.DevIp)
            {
                //重置时插入最后一条记录
                recState.oldV = cs.DC_outputVolt;
                recState.oldA = cs.DC_loadCurrent;
                recState.count = -1;
                worktype = 101;
                recState.needInsert = true;
                //等待插入工作完成
                while (worktype != 100)
                {
                    continue;
                }
                //重置后的第一条记录
                if (continueSeq != 0)
                {
                    continueSeq = 0;//重置工步时接续包序清0
                }
                if (pauseSeq != 0)
                {
                    pauseSeq = 0;//重置工步时暂停包序清0
                }
                recState.curTotalCount = 0;//清除每个工步总的接收数据条数
                recState.beginSeq = currSeq + 1;//更新该工步的起始包序
                recState.oldA = cs.DC_loadCurrent;
                recState.oldV = cs.DC_outputVolt;
                recState.count = -1;
                recState.needInsert = true;
                //如果当前工步的工步名发生了改变，则需要下发新的当前工步参数指令
                if (stepSetInfo.StepList[stepNum - 1].StepName != sp.StepList[stepNum - 1].StepName)
                {
                    //更新工步列表和保护条件
                    stepSetInfo.StepList = sp.StepList;
                    //DateTime oldTime = beginTime;
                    CommandData(stepNum - 1);
                    //beginTime = oldTime;
                    if (RecordJump == "1")
                    {
                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "用户点击重置工步", "跳转到" + stepSetInfo.StepList[stepNum - 1].StepName + "工步");
                        queJump.Enqueue(jumpReason);
                    }
                }
                else
                {
                    beginTime = System.DateTime.Now;
                    //更新工步列表和保护条件
                    stepSetInfo.StepList = sp.StepList;
                }
                //更新各工步的如果工步和记录条件工步数据
                for (int i = 0; i < sp.StepList.Count - 1; i++)
                {
                    List<JumpCondition> jcList = new List<JumpCondition>();
                    List<RecordCondition> recList = new List<RecordCondition>();
                    if (stepSetInfo.StepList[i].CutoffCurr != null)
                    {
                        jcList = StepRunControl.GetCutOffCurrCondition(Convert.ToSingle(stepSetInfo.StepList[i].CutoffCurr), stepSetInfo, jcList, i);
                    }
                    //各工步的保护条件也按照如果工步来处理
                    //jcList = StepRunControl.GetProctCondition(stepSetInfo, jcList,i+1);
                    if (stepSetInfo.StepList[i].ChildList != null)
                    {
                        //获取当前工步的如果工步和记录条件工步数据
                        for (int j = 0; j < stepSetInfo.StepList[i].ChildList.Count; j++)
                        {
                            if (stepSetInfo.StepList[i].ChildList[j].ChildStepName == "如果")
                            {
                                jcList.Add(StepRunControl.GetStepJumpCondition(stepSetInfo, i, j));
                            }
                            else if (stepSetInfo.StepList[i].ChildList[j].ChildStepName == "记录条件")
                            {
                                recList.Add(StepRunControl.GetStepRecordCondition(stepSetInfo, i, j));
                            }
                        }
                    }
                    if (!allJcDic.ContainsKey(i))
                    {
                        allJcDic.Add(i, jcList);
                        allRecDic.Add(i, recList);
                    }
                    else
                    {
                        allJcDic[i] = jcList;
                        allRecDic[i] = recList;
                    }
                }
            }
        }
        /// <summary>
        /// 监听到故障后触发的事件
        /// </summary>
        /// <param name="i"></param>
        /// <param name="stepNum"></param>
        /// <param name="gid"></param>
        public void ErrorOccurs(string ip, int cid, int stepNum, int Mid, CommandProtocol.IndependAction inAction, CommandProtocol.ParalleAction paAction, bool isParalle)
        {
            if (ip == stepSetInfo.DevIp && cid == stepSetInfo.Cid - 1 && Mid == stepSetInfo.Mid - 1)
            {
                currentState = "故障";
                Closing();
                if (RecordJump == "1")
                {
                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "发生故障", "跳转到故障状态");
                    queJump.Enqueue(jumpReason);
                }
            }
        }
        /// <summary>
        /// 用户点击关机后触发的事件
        /// </summary>
        public void UserClosing(int realid, string ip, bool isMove)
        {
            if ((realid == this.stepSetInfo.RealId || realid == -1) && ip == this.stepSetInfo.DevIp)
            {
                //如果是由迁移引发的关机，则需插入一条数据
                if (isMove)
                {
                    //迁移时插入最后一条记录
                    recState.oldV = cs.DC_outputVolt;
                    recState.oldA = cs.DC_loadCurrent;
                    recState.count = -1;
                    worktype = 104;
                    recState.needInsert = true;
                    //等待插入工作完成
                    while (worktype != 100)
                    {
                        continue;
                    }
                }
                currentState = "结束";
                Closing();
                if (isMove)
                {
                    if (RecordJump == "1")
                    {
                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                    stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "用户点击迁移", "跳转到完成状态");
                        queJump.Enqueue(jumpReason);
                    }
                }
                else
                {
                    if (RecordJump == "1")
                    {

                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        string closingReason = "用户点击关机";
                        if (realid == -1)
                        {
                            closingReason = "丢包造成的关机";
                        }
                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                    stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), closingReason, "跳转到完成状态");
                        queJump.Enqueue(jumpReason);
                    }
                }
            }
        }
        /// <summary>
        /// 突然断网,将对应Ip下的所有通道置为完成状态
        /// </summary>
        /// <param name="ip"></param>
        public void NetClosing(string ip)
        {
            if (ip == this.stepSetInfo.DevIp)
            {
                runState.isClosed = true;
                runState.isRunning = false;
                DateTime endTime = System.DateTime.Now;
                //关闭控制数据传输的定时器
                if (timerShow != null)
                {
                    timerShow.Close();
                }
                //改变通道显示状态
                currentState = "结束";
                runState.isChanged = true;
                runState.needShow = true;
                ThreadPool.QueueUserWorkItem(new WaitCallback(ShowView));

                System.Timers.Timer timerLast = new System.Timers.Timer(5000);
                timerLast.Elapsed += (s, ela) =>
                {
                    //所有工步线程结束
                    runState.isClosed = false;
                    runState.isOver = true;
                    //删除委托
                    CloseDelete();
                    if (timerInsertData != null)
                    {
                        timerInsertData.Close();
                    }
                    InsertChannelData();//将队列中剩余的数据插入到数据库中
                };
                timerLast.AutoReset = false;
                timerLast.Enabled = true;
                timerLast.Start();
                //更新Test表
                CheckLogControl.WriteToDeviceLog("testFinish", stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid);//写入设备日志
                TestHelper.UpdateTestEndTime(stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid, endTime);

                if (RecordJump == "1")
                {
                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "网线意外断开", "跳转到完成状态");
                    queJump.Enqueue(jumpReason);
                }
            }
        }
        /// <summary>
        /// 用户点击跳转后触发的事件
        /// </summary>
        public void UserJumping(int realid, string ip, int jumpStep)
        {
            if (realid == this.stepSetInfo.RealId && ip == this.stepSetInfo.DevIp)
            {
                if (stepSetInfo.StepList[stepNum - 1].StepName == "斜坡工况" || stepSetInfo.StepList[stepNum - 1].StepName == "脉冲工况")
                {
                    runState.isConditionIfJump = true;
                }
                //下发新工步参数，更新工步开始时间
                beginTime = default(DateTime);
                if (RecordJump == "1")
                {
                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                        stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "用户点击跳转", "跳转到" + stepSetInfo.StepList[jumpStep - 1].StepName + "工步");
                    queJump.Enqueue(jumpReason);
                }
                stepNum = Convert.ToInt32(jumpStep);
                CommandData(stepNum - 1);
            }
        }
        #endregion
        #region 关机流程
        /// <summary>
        /// 结束时删除委托
        /// </summary>
        private void CloseDelete()
        {
            StartListen.ReceiveChannelData -= new StartListen.ReceiveData(ProcessData);
            StartListen.ReceiveCondiRequest -= new StartListen.ReceiveCondiReq(ProcessCondiReq);
            IndexPage.StopByUser -= new IndexPage.UserStop(Pause);
            IndexPage.NewStep -= new IndexPage.StepUpdate(UpdateStep);
            TcpControl.ChannelErrorCloseJudge -= new TcpControl.ErrorCloseJudge(ErrorOccurs);
            IndexPage.CloseByUser -= new IndexPage.UserClose(UserClosing);
            IndexPage.JumpByUser -= new IndexPage.UserJump(UserJumping);
            StartListen.CloseByUser -= new StartListen.UserClose(UserClosing);
            StartListen.NetDisConnect -= new StartListen.NetClose(NetClosing);
        }
        /// <summary>
        /// 关机流程
        /// </summary>
        private void Closing()
        {
            //工步停止执行，只有存储数据线程仍在执行
            runState.isClosed = true;
            runState.isRunning = false;
            DateTime endTime = System.DateTime.Now;
            //此时存储的数据都归到结束工步中
            stepNum = stepSetInfo.StepList.Count;
            if (!runState.isParalle)
            {
                //发送关机指令
                inAction.stepNum = stepNum - 1;
                inAction = StepRunControl.IndependentClose(inAction, temp, client);
                //Thread.Sleep(10);
                //触发关机校验委托事件
                OnCloseJudge(stepSetInfo.DevIp, stepSetInfo.Cid - 1, stepNum, stepSetInfo.Mid - 1, inAction, paAction, false);
            }
            else
            {
                //并联使能包撤回
                paPulse = StepRunControl.ParallePulseBack(paPulse, temp, client);
                //Thread.Sleep(10);
                //发送关机指令
                paAction.stepNum = stepNum - 1;
                paAction = StepRunControl.ParalleClose(paAction, temp, client);
                //Thread.Sleep(10);
                //触发关机校验委托事件
                OnCloseJudge(stepSetInfo.DevIp, stepSetInfo.Cid - 1, stepNum, stepSetInfo.Mid - 1, inAction, paAction, true);
            }
            //关闭控制数据传输的定时器
            if (timerShow != null)
            {
                timerShow.Close();
            }
            //改变通道显示状态
            runState.isChanged = true;
            runState.needShow = true;
            ThreadPool.QueueUserWorkItem(new WaitCallback(ShowView));

            System.Timers.Timer timerLast = new System.Timers.Timer(5000);
            timerLast.Elapsed += (s, ela) =>
            {
                //所有工步线程结束
                runState.isClosed = false;
                runState.isOver = true;
                //删除委托
                CloseDelete();
                if (timerInsertData != null)
                {
                    timerInsertData.Close();
                }
                InsertChannelData();//将队列中剩余的数据插入到数据库中
            };
            timerLast.AutoReset = false;
            timerLast.Enabled = true;
            timerLast.Start();
            //更新Test表
            CheckLogControl.WriteToDeviceLog("testFinish", stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid);//写入设备日志
            TestHelper.UpdateTestEndTime(stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid, endTime);
        }
        #endregion

        #region 存储数据线程
        //<summary>
        //将数据库
        //</summary>
        //<param name="state"></param>
        public void SaveData(object state)
        {
            recState.count++;
            if (!queCList.IsEmpty)
            {
                List<ChannelState> csList = new List<ChannelState>();
                lock (savaDataObj)
                {
                    if (queCList.TryDequeue(out csList))
                    {
                        int currNum = csList[0].CurrStepNum;//当前工步号
                        int seqId = 0;
                        if (csList.Count > 0)
                        {
                            if (csList[0].ContinueSeq != 0)
                            {
                                seqId = csList[0].CurrentSeq - (csList[0].ContinueSeq - csList[0].PauseSeq) - 2;//接续以后保持相对时间以暂停时的为基准
                            }
                            else//有可能在执行当前savaData线程过程中已经切换到下一个工步，此时continueSeq=0,recState.beginSeq更新变大了
                            {
                                seqId = csList[0].CurrentSeq;
                            }
                        }
                        List<AuxChannel> auxState = stepSetInfo.ChlList[stepSetInfo.Cid - 1].auxChannel;
                        List<AuxChannel> aux = new List<AuxChannel>();
                        for (int i = 0; i < auxState.Count; i++)
                        {
                            AuxChannel auxChl = new AuxChannel();
                            auxChl.auxId = auxState[i].auxId;
                            auxChl.voltage = auxState[i].voltage;
                            auxChl.temperature1 = auxState[i].temperature1;
                            auxChl.temperature2 = auxState[i].temperature2;
                            auxChl.temperature3 = auxState[i].temperature3;
                            aux.Add(auxChl);
                        }
                        //如果是强制要求存储的数据，则不管记录条件直接存储
                        if (recState.needInsert)
                        {
                            recState.needInsert = false;
                            ChannelData chlData = null;
                            string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                            RecordState newRecState = CloneModel<RecordState>(recState);//先进行深度赋值，防止recState值被修改对前面的数据产生影响
                            if (runState.isClosed)
                            {
                                chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, true);
                            }
                            else
                            {
                                chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, false);
                            }
                            lock (synObj)
                            {
                                ChannelData newChlData = CloneModel<ChannelData>(chlData);
                                queData.Enqueue(newChlData);
                            }
                            if (worktype != 100)
                            {
                                worktype = 100;
                            }
                        }
                        //如果当前工步有记录条件，判断是否在记录条件范围内
                        if (allRecDic.ContainsKey(currNum - 1) && allRecDic[currNum - 1].Count > 0)
                        {
                            bool[] isInField = new bool[allRecDic[currNum - 1].Count];
                            List<RecordCondition> recCond = allRecDic[currNum - 1];
                            for (int i = 0; i < recCond.Count; i++)
                            {
                                //判断是否在需要记录的范围内
                                if (recCond[i].RecordCond == "时间段")
                                {
                                    TimeSpan ts = StepRunControl.GetStepRunTime(beginTime, contiTime, nowTime, executionTime);
                                    //如果在时间范围内
                                    if (ts.TotalMilliseconds > (Convert.ToSingle(recCond[i].CondLower) * 1000) && ts.TotalMilliseconds <= (Convert.ToSingle(recCond[i].CondUpper) * 1000))
                                    {
                                        isInField[i] = true;
                                    }
                                }
                                else if (recCond[i].RecordCond == "电压段")
                                {
                                    //如果在电压范围内
                                    if (cs.DC_outputVolt > Convert.ToSingle(recCond[i].CondLower) && cs.DC_outputVolt <= Convert.ToSingle(recCond[i].CondUpper))
                                    {
                                        isInField[i] = true;
                                    }
                                }
                                else if (recCond[i].RecordCond == "电流段")
                                {
                                    //如果在电流范围内
                                    if (cs.DC_loadCurrent > Convert.ToSingle(recCond[i].CondLower) && cs.DC_loadCurrent <= Convert.ToSingle(recCond[i].CondUpper))
                                    {
                                        isInField[i] = true;
                                    }
                                }
                                //如果在范围内，则按照该记录条件工步的条件来记录
                                if (isInField[i])
                                {
                                    recState = StepRunControl.RecordByInterval(Convert.ToSingle(recCond[i].TimeInterval), Convert.ToSingle(recCond[i].VolInterval), Convert.ToSingle(recCond[i].CurrInterval), recState, cs, seqId, csList[0].BeginSeq);
                                    if (recState.needInsert)
                                    {
                                        recState.needInsert = false;
                                        ChannelData chlData = null;
                                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                        RecordState newRecState = CloneModel<RecordState>(recState);//先进行深度赋值，防止recState值被修改对前面的数据产生影响
                                        if (runState.isClosed)
                                        {
                                            chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, true);
                                        }
                                        else
                                        {
                                            chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, false);
                                        }
                                        lock (synObj)
                                        {
                                            ChannelData newChlData = CloneModel<ChannelData>(chlData);
                                            queData.Enqueue(newChlData);
                                        }
                                        if (worktype != 100)
                                        {
                                            worktype = 100;
                                        }
                                    }
                                }
                            }
                            //判断是否有工步记录条件满足
                            bool totalInField = false;
                            for (int j = 0; j < isInField.Length; j++)
                            {
                                if (isInField[j] == true)
                                {
                                    totalInField = true;
                                    break;
                                }
                            }
                            //如果所有的记录条件范围都不满足，则按照保护条件中的记录条件来记录
                            if (!totalInField)
                            {
                                recState = StepRunControl.RecordByInterval(timeInterval, volInterval, currInterval, recState, cs, seqId, csList[0].BeginSeq);
                                if (recState.needInsert)
                                {
                                    recState.needInsert = false;
                                    ChannelData chlData = null;
                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                    RecordState newRecState = CloneModel<RecordState>(recState);//先进行深度赋值，防止recState值被修改对前面的数据产生影响
                                    if (runState.isClosed)
                                    {
                                        chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, true);
                                    }
                                    else
                                    {
                                        chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, false);
                                    }
                                    lock (synObj)
                                    {
                                        ChannelData newChlData = CloneModel<ChannelData>(chlData);
                                        queData.Enqueue(newChlData);
                                    }
                                    if (worktype != 100)
                                    {
                                        worktype = 100;
                                    }
                                }
                            }
                        }
                        //如果当前工步没有记录条件，则按照保护条件中的记录条件来记录
                        else
                        {
                            recState = StepRunControl.RecordByInterval(timeInterval, volInterval, currInterval, recState, cs, seqId, csList[0].BeginSeq);
                            if (recState.needInsert)
                            {
                                recState.needInsert = false;
                                ChannelData chlData = null;
                                string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                RecordState newRecState = CloneModel<RecordState>(recState);//先进行深度赋值，防止recState值被修改对前面的数据产生影响
                                if (runState.isClosed)
                                {
                                    chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, true);
                                }
                                else
                                {
                                    chlData = new ChannelData(csList, newRecState.curTotalCount, currNum, circStr, worktype, aux, false);
                                }
                                lock (synObj)
                                {
                                    ChannelData newChlData = CloneModel<ChannelData>(chlData);
                                    queData.Enqueue(newChlData);
                                }
                                if (worktype != 100)
                                {
                                    worktype = 100;
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #region 插入数据库方法
        /// <summary>
        /// 将队列中存储的数据插入数据库channeldata表和jumplog表
        /// </summary>
        public void InsertChannelData()
        {
            string fileName = stepSetInfo.DevIp + "-" + stepSetInfo.Cid;
            DataTable dt = new DataTable();
            dt.TableName = tableName;
            StepRunControl.setDataTableColumn(dt);//给dt赋值列名
            int stepType = -1;//工步类型
            string lastStepName = "";//上一个工步名称
            List<string> SQLStringList = new List<string>();//存放sql语句
            int pulseNum = 0;//累加脉冲段号
            int lastPulseNum = -1;//记录上一个不同的脉冲段号
            int queLength = queData.Count;//队列中目前的元素个数
            //Console.WriteLine("time2:" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
            for (int i = 0; i < queLength; i++)
            {
                if (!runState.isParalle)
                {
                    ChannelData chlData = null;
                    queData.TryDequeue(out chlData);
                    if (chlData != null)
                    {
                        string testId = stepSetInfo.TestId;
                        string stepName = stepSetInfo.StepList[chlData.stepNum - 1].StepName;
                        if (!stepName.Equals(lastStepName))
                        {
                            stepType = DicHelper.RetrieveStepCode(stepName);
                            lastStepName = stepName;
                        }
                        ChannelState channelState = chlData.csList[0];
                        //如果是脉冲工况以外的包,则该包的脉冲段号无效
                        if (stepType != 16)
                        {
                            channelState.pulseNumber = -1;
                        }
                        else
                        {
                            //如果是脉冲包，则脉冲段号累加1
                            if (channelState.pulseNumber != lastPulseNum)
                            {
                                lastPulseNum = channelState.pulseNumber;
                                channelState.pulseNumber = pulseNum;
                                pulseNum++;
                            }
                            //如果是脉冲工况内的非脉冲包,则该包的脉冲段号不变
                            else
                            {
                                lastPulseNum = channelState.pulseNumber;
                                channelState.pulseNumber = pulseNum;
                            }
                        }
                        //方法一：
                        StepRunControl.setDataTableRows(dt, channelState, chlData.circ, testId, 1, chlData.stepNum, stepType, chlData.worktype, chlData.totalCount * 10, "", chlData.isExtra, chlData.aux);
                        //方法二： 
                        //string sql = string.Format("insert into " + tableName + "(pulse_num,test_id,test_mode,mid_id,cabinet_id,channel_num,isAll,step_num,step_type,work_type,cycle,test_time,Channel_efficiency,DC_outputVolt," +
                        //        "DC_loadCurrent,Load_temper1,Load_temper2,DC_busVolt,Charge_cap,Discharge_cap,Total_cap,Step_time,Charge_energy,Discharge_energy,Total_energy,power,Diff_volt,Diff_current," +
                        //        "Aux_data,Status_data,Sys_time,isExtra) values({0},'{1}',{2},{3},{4},'{5}',{6},{7},{8},{9},'{10}',{11},{12},{13},{14},{15},{16},{17},{18}," +
                        //        "{19},{20},{21},{22},{23},{24},{25},{26},{27},'{28}','{29}','{30}',{31});",
                        //        channelState.pulseNumber, testId, 1, channelState.MID + 1, channelState.GID + 1, cid, isAll, stepNum, stepType, chlData.worktype, chlData.circ, chlData.totalCount * 10, channelState.channelEfficiency, channelState.DC_outputVolt, channelState.DC_loadCurrent, channelState.DC_loadTemper, channelState.DC_ambientTemper, channelState.DC_busVolt,
                        //        channelState.chargeCap, channelState.dischargeCap, channelState.totalCap, channelState.stepTime, channelState.chargeEnergy, channelState.dischargeEnergy, channelState.totalEnergy, channelState.power, channelState.diffVolt, channelState.diffCurrent, JsonHelper.Serialize(chlData.aux), channelState.faultStatus, channelState.time, isExtra);
                        //SQLStringList.Add(sql);
                    }
                }
                else
                {
                    string testId = stepSetInfo.TestId;
                    string stepName;
                    ChannelData parachlData = null;
                    queData.TryDequeue(out parachlData);
                    if (parachlData != null)
                    {
                        stepName = stepSetInfo.StepList[parachlData.stepNum - 1].StepName;
                        if (!stepName.Equals(lastStepName))
                        {
                            stepType = DicHelper.RetrieveStepCode(stepName);
                            lastStepName = stepName;
                        }
                        for (int j = 0; j < parachlData.csList.Count; j++)
                        {
                            ChannelState channelState = parachlData.csList[j];
                            //如果是脉冲工况以外的包,则该包的脉冲段号无效
                            if (stepType != 16)
                            {
                                channelState.pulseNumber = -1;
                            }
                            else
                            {
                                //如果是脉冲包，则脉冲段号累加1
                                if (channelState.pulseNumber != lastPulseNum)
                                {
                                    lastPulseNum = channelState.pulseNumber;
                                    channelState.pulseNumber = pulseNum;
                                    pulseNum++;
                                }
                                //如果是脉冲工况内的非脉冲包,则该包的脉冲段号不变
                                else
                                {
                                    lastPulseNum = channelState.pulseNumber;
                                    channelState.pulseNumber = pulseNum;
                                }
                            }
                            if (j != parachlData.csList.Count - 1)
                            {
                                StepRunControl.setDataTableRows(dt, channelState, parachlData.circ, testId, 1, parachlData.stepNum, stepType, parachlData.worktype, parachlData.totalCount * 10, "", parachlData.isExtra, parachlData.aux);
                            }
                            else
                            {
                                StepRunControl.setDataTableRows(dt, channelState, parachlData.circ, testId, 1, parachlData.stepNum, stepType, parachlData.worktype, parachlData.totalCount * 10, paStr, parachlData.isExtra, parachlData.aux);
                            }
                        }
                    }
                }
            }
            //Console.WriteLine("time3:" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
            //将数据批量插入数据库
            lock (insertObj)
            {
                int insertCount = ChannelDataHelper.BulkInsert(dt, fileName);// MySqlBulkLoader批量插入数据库
                currentRecordCount += insertCount;//当前总记录条数\
                //查询当前测试总记录条数            
                //int recordNum = ChannelDataHelper.GetRecordNums(stepSetInfo);
                int recordNum = currentRecordCount;
                //更新测试表记录条数
                TestHelper.UpdateTestRecordNum(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid, recordNum);
            }
            //ChannelDataHelper.InsertChannelData(SQLStringList);//多条sql语句同时插入
            if (queJump.Count > 0)
            {
                JumpReasonRecord jumpReason = queJump.Dequeue();
                JumpReasonRecordControl.InsertNewJumpReason(jumpReason);
            }
        }
        #endregion

        #region 现在的通道状态变化线程
        //<summary>
        //运行过程中的通道状态变化线程
        //</summary>
        //<param name="state"></param>
        public void ShowViewRunning(object state)
        {
            string getState = currentState;
            //为防止第一工步的状态将开机中状态覆盖，通过传参来实现开机中状态
            if (state != null)
            {
                getState = (string)state;
            }
            //如果工步发生了切换，则改变通道颜色
            if (runState.isChanged)
            {
                //如果是开机中状态，则不需要将isChanged置为false,因为通道还需要变成第一工步状态
                if (state == null)
                {
                    runState.isChanged = false;
                }
                OnColorChange(getState, stepSetInfo.RealId, chl);//改变通道颜色 
            }
            lock (showViewObj)
            {
                ChannelState newcs = null;
                if (!queCS.IsEmpty)
                {
                    if (queCS.TryDequeue(out newcs))
                    {
                        int currNum = stepNum;//获取当前工步序号
                        //获取当前工步运行时间
                        TimeSpan ts = StepRunControl.GetStepRunTime(newcs.BeginTime, newcs.ContiTime, newcs.NowTime, newcs.ExecutionTime);
                        chl.StepTime = Convert.ToString(ts).Substring(0, 8);//工步执行时间 
                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        chl = StepRunControl.PrepareDataToShow(chl, stepSetInfo, currNum, circStr, newcs, getState, runState);
                        OnSendParams(getState, chl, stepSetInfo.RealId);//传递参数到主程序
                    }
                }
            }

        }
        /// <summary>
        /// 其他情况下的通道状态变化线程，如（停止，结束）
        /// </summary>
        /// <param name="state"></param>
        public void ShowView(object state)
        {
            lock (showViewObj)
            {
                string getState = currentState;
                //如果工步发生了切换，则改变通道颜色
                if (runState.isChanged)
                {
                    runState.isChanged = false;
                    OnColorChange(getState, stepSetInfo.RealId, chl);//改变通道颜色 
                }
                //准备给IndexPage中通道显示用的数据

                int currNum = stepNum;//获取当前工步序号
                //获取当前工步运行时间
                TimeSpan ts = StepRunControl.GetStepRunTime(cs.BeginTime, cs.ContiTime, cs.NowTime, cs.ExecutionTime);
                chl.StepTime = Convert.ToString(ts).Substring(0, 8);//工步执行时间 
                string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                chl = StepRunControl.PrepareDataToShow(chl, stepSetInfo, currNum, circStr, cs, getState, runState);
                OnSendParams(getState, chl, stepSetInfo.RealId);//传递参数到主程序
            }
        }
        #endregion
        public static T CloneModel<T>(T oModel)
        {
            var oRes = default(T);
            var oType = typeof(T);

            //得到新的对象对象
            oRes = (T)Activator.CreateInstance(oType);

            //给新的对象复制
            var lstPro = oType.GetProperties();
            foreach (var oPro in lstPro)
            {
                //从旧对象里面取值
                var oValue = oPro.GetValue(oModel);

                //复制给新的对象
                oPro.SetValue(oRes, oValue);
            }

            return oRes;
        }

        #region 工步切换的判断
        /// <summary>
        /// 工步切换线程
        /// </summary>
        /// <param name="state"></param>
        public void StepJudge(object state)
        {
            List<StepInfo> stepList = (List<StepInfo>)state;
            //获取当前工步运行时间
            TimeSpan ts = StepRunControl.GetStepRunTime(beginTime, contiTime, nowTime, executionTime);
            int currNum = stepNum;
            //当遇到循环工步时，用多个工步顺序执行来代替
            if (stepList[currNum - 1].StepName != "循环")
            {
                if (allJcDic.ContainsKey(currNum - 1) && allJcDic[currNum - 1].Count > 0)
                {
                    lock (synJudgeObj)
                    {
                        ConditionJump(currNum - 1, ts);
                    }
                }
                //当前工步不存在条件工步子节点时，根据时间间隔判断，若时间超过，则进入下一工步
                if (currNum < stepList.Count)
                {
                    if (stepList[currNum - 1].StepTime != null)
                    {
                        TimeSpan stepTime = new TimeSpan(0, 0, 0, 0, (Convert.ToInt32(stepList[currNum - 1].StepTime)));
                        if (ts >= stepTime || (stepTime - ts) < new TimeSpan(0, 0, 0, 0, 10))
                        {
                            //工步切换，清空单点暂停和接续的时间
                            if (contiTime != default(DateTime))
                            {
                                contiTime = default(DateTime);
                            }
                            if (stepSetInfo.StepList[currNum - 1].StepName == "斜坡工况" || stepSetInfo.StepList[currNum - 1].StepName == "脉冲工况")
                            {
                                runState.isConditionTimeOut = true;
                                if (RecordJump == "1")
                                {
                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "工况执行时间达到", "跳转到" + stepSetInfo.StepList[stepNum].StepName + "工步");
                                    queJump.Enqueue(jumpReason);
                                }
                            }
                            else
                            {
                                beginTime = default(DateTime);
                                if (RecordJump == "1")
                                {
                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "工步时间达到", "跳转到" + stepSetInfo.StepList[stepNum].StepName + "工步");
                                    queJump.Enqueue(jumpReason);
                                }
                                //工步号加1
                                stepNum++;
                                //下发工步参数指令
                                CommandData(stepNum - 1);

                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 如果工步跳转判断
        /// </summary>
        /// <param name="index"></param>
        private void ConditionJump(int index, TimeSpan ts)
        {
            //存储多个“与”关系的条件工步的跳转状态
            List<Boolean> multiJc = new List<Boolean>();
            //记录跳转条件是否达成
            bool[] jump = new bool[allJcDic[index].Count];
            //遍历条件工步
            for (int j = 0; j < allJcDic[index].Count; j++)
            {
                bool finished = false;
                //根据跳转条件获取需要比较的状态值
                float status = 0;
                switch (allJcDic[index][j].JumpCond)
                {
                    case "电池电压":
                        status = cs.DC_outputVolt;
                        break;
                    case "电池电流":
                        status = Math.Abs(cs.DC_loadCurrent);
                        break;
                    case "容量":
                        status = Math.Abs(cs.totalCap);
                        break;
                    case "能量":
                        status = Math.Abs(cs.totalEnergy);
                        break;
                    case "工步时间":
                        status = Convert.ToSingle(ts.TotalSeconds);
                        break;
                    case "主通道温度":
                        break;
                    case "持续时间":
                        if (jump[j - 1])
                        {
                            if (!runState.isContiTimeStart)
                            {
                                runState.isContiTimeStart = true;
                                durationBeginTime = System.DateTime.Now;
                                status = 0;
                            }
                            else
                            {
                                TimeSpan durationTime = System.DateTime.Now.Subtract(durationBeginTime);
                                status = Convert.ToSingle(durationTime.TotalSeconds);
                            }
                        }
                        else
                        {
                            runState.isContiTimeStart = false;
                            status = 0;
                        }
                        break;
                    case "环境温度":
                        status = Convert.ToSingle(cs.DC_ambientTemper);
                        break;
                }
                //根据操作符判断跳转条件是否达成
                jump[j] = StepRunControl.JudgeSuccess(j, allJcDic[index], status, jump);
                switch (allJcDic[index][j].JumpTo)
                {
                    //如果跳转目标为“与（&）”，记录jump，到下一个条件工步
                    case "与(&)":
                        {
                            multiJc.Add(jump[j]);
                            finished = false;
                        }
                        break;
                    //如果跳转目标为不为与，则考虑两种情况。
                    //1.该条件工步与前面的条件工步为“与”关系。遍历multiJc,只要有一个值为false,跳转条件不成立。
                    //2.该条件工步与前面的条件工步为“或”关系或前面没有工步。只要该条件工步成立，则跳转条件成立。
                    default:
                        {
                            if (jump[j] == true)
                            {
                                finished = true;
                                //如果该工步与前面的条件工步为“与”关系，则遍历multiJc
                                if (multiJc.Count > 0)
                                {
                                    for (int n = 0; n < multiJc.Count; n++)
                                    {
                                        if (multiJc[n] == false)
                                        {
                                            finished = false;
                                            break;
                                        }
                                    }
                                }
                                //跳转成功
                                if (finished)
                                {
                                    //拆分goto语句，得到跳转目标
                                    string[] states = (allJcDic[index][j].JumpTo).Split(new Char[] { ':' });
                                    switch (states[1])
                                    {
                                        case "完成":
                                            {
                                                //通道变为完成状态，进入关机流程
                                                currentState = "结束";
                                                Closing();
                                                string reason = GetJumpReason(index, multiJc, j);
                                                if (RecordJump == "1")
                                                {
                                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                                        stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), reason, "跳转到完成状态");
                                                    queJump.Enqueue(jumpReason);
                                                }
                                            }
                                            break;
                                        case "保护":
                                            {
                                                //通道进入保护状态，进入关机流程,记录故障
                                                currentState = "保护";
                                                Closing();
                                                string reason = GetJumpReason(index, multiJc, j);
                                                if (RecordJump == "1")
                                                {
                                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                                        stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), reason, "跳转到保护状态");
                                                    queJump.Enqueue(jumpReason);
                                                }
                                            }
                                            break;
                                        case "停止":
                                            {
                                                currentState = "停止";
                                                runState.isChanged = true;
                                                runState.isRunning = false;
                                                runState.needShow = true;
                                                //到达停止状态，通道变化状态
                                                ThreadPool.QueueUserWorkItem(new WaitCallback(ShowView));
                                                if (!runState.isParalle)
                                                {
                                                    inAction.stepNum = index;
                                                    inAction = StepRunControl.IndependentStop(inAction, temp, client);
                                                }
                                                else
                                                {
                                                    paAction.stepNum = index;
                                                    paAction = StepRunControl.ParalleStop(paAction, temp, client);
                                                }
                                                string reason = GetJumpReason(index, multiJc, j);
                                                if (RecordJump == "1")
                                                {
                                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                                        stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), reason, "跳转到暂停状态");
                                                    queJump.Enqueue(jumpReason);
                                                }
                                            }
                                            break;
                                        default:
                                            {
                                                if (stepSetInfo.StepList[stepNum - 1].StepName == "斜坡工况" || stepSetInfo.StepList[stepNum - 1].StepName == "脉冲工况")
                                                {
                                                    runState.isConditionIfJump = true;
                                                }
                                                //下发新工步参数，更新工步开始时间
                                                beginTime = default(DateTime);
                                                string reason = GetJumpReason(index, multiJc, j);
                                                if (RecordJump == "1")
                                                {
                                                    string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                                    JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                                        stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), reason, "跳转到" + stepSetInfo.StepList[Convert.ToInt32(states[1]) - 1].StepName + "工步");
                                                    queJump.Enqueue(jumpReason);
                                                }
                                                stepNum = Convert.ToInt32(states[1]);
                                                CommandData(stepNum - 1);
                                            }
                                            break;
                                    }
                                }
                            }
                            else
                            {
                                finished = false;
                            }
                            multiJc.Clear();
                        }
                        break;
                }
                if (finished)
                {
                    break;
                }
            }
        }
        /// <summary>
        /// 获取如果工步跳转原因
        /// </summary>
        /// <param name="index"></param>
        /// <param name="multiJc"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        private string GetJumpReason(int index, List<Boolean> multiJc, int j)
        {
            string reason = null;
            if (multiJc.Count > 0)
            {
                for (int i = multiJc.Count; i >= 0; i--)
                {
                    if (i != 0)
                    {
                        reason += allJcDic[index][j - i].JumpCond + allJcDic[index][j - i].JumpOperator + allJcDic[index][j - i].JumpValue + SetReasonUnit(allJcDic[index][j - i].JumpCond) + " 与 ";
                    }
                    else
                    {
                        reason += allJcDic[index][j].JumpCond + allJcDic[index][j].JumpOperator + allJcDic[index][j].JumpValue + SetReasonUnit(allJcDic[index][j].JumpCond);
                    }
                }
            }
            else
            {
                reason = allJcDic[index][j].JumpCond + allJcDic[index][j].JumpOperator + allJcDic[index][j].JumpValue + SetReasonUnit(allJcDic[index][j].JumpCond);
            }
            return reason;
        }
        /// <summary>
        /// 增加如果工步跳转的单位
        /// </summary>
        /// <param name="jumpCond"></param>
        /// <returns></returns>
        private string SetReasonUnit(string jumpCond)
        {
            string unit = null;
            switch (jumpCond)
            {
                case "电池电压":
                    unit = "V";
                    break;
                case "电池电流":
                    unit = "A";
                    break;
                case "容量":
                    unit = "Ah";
                    break;
                case "能量":
                    unit = "Wh";
                    break;
                case "工步时间":
                case "持续时间":
                    unit = "s";
                    break;
                case "主通道温度":
                case "环境温度":
                    break;
            }
            return unit;
        }
        #endregion
        #region 工步切换时的操作
        /// <summary>
        /// 工步切换时的操作
        /// </summary>
        /// <param name="index"></param>
        private void CommandData(int index)
        {
            if (index != stepSetInfo.StartStep - 1)
            {
                if (continueSeq != 0)
                {
                    continueSeq = 0;//工步切换时接续包序清0
                }
                if (pauseSeq != 0)
                {
                    pauseSeq = 0;//工步切换时暂停包序清0
                }
                recState.curTotalCount = 0;//清除每个工步总的接收数据条数
                recState.beginSeq = currSeq + 1;
                recState.count = -1;
                recState.oldA = cs.DC_loadCurrent;
                recState.oldV = cs.DC_outputVolt;
                recState.needInsert = true;
            }
            runState.isContiTimeStart = false;
            string stepName = stepSetInfo.StepList[index].StepName;
            int currNum = index + 1;
            //如果为专业工步，则切换工步时需要更新保护条件
            if (!stepSetInfo.isStandard)
            {
                timeInterval = Convert.ToSingle(stepSetInfo.StepList[index].ProtCondition.TimeSpan) * 1000;
                volInterval = Convert.ToSingle(stepSetInfo.StepList[index].ProtCondition.VoltageSpan);
                currInterval = Convert.ToSingle(stepSetInfo.StepList[index].ProtCondition.CurrentSpan);
            }
            if (timeInterval == 0 && volInterval == 0 && currInterval == 0)
            {
                timeInterval = 100;
            }
            switch (stepName)
            {
                case "循环":
                    {
                        if (!runState.isParalle)
                        {
                            inPara.commandUpdata = !inPara.commandUpdata;
                        }
                        else
                        {
                            paPara.commandUpdata = !paPara.commandUpdata;
                        }
                        //获取起始工步号和循环次数
                        int beginIndex = Convert.ToInt32(stepSetInfo.StepList[index].Voltage) - 1;
                        int circNum = Convert.ToInt32(stepSetInfo.StepList[index].Cap);
                        //circ++;
                        //stepSetInfo.StepList[index].circNum++;
                        circDic[index] = circDic[index] + 1;
                        int circTime = circDic[index];
                        if (circTime < circNum)
                        {
                            beginTime = default(DateTime);
                            if (RecordJump == "1")
                            {
                                string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "遇到循环工步", "跳转到" + stepSetInfo.StepList[beginIndex].StepName + "工步");
                                queJump.Enqueue(jumpReason);
                            }
                            stepNum = beginIndex + 1;
                            CommandData(stepNum - 1);
                        }
                        else
                        {
                            beginTime = default(DateTime);
                            if (RecordJump == "1")
                            {
                                string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                                JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "循环工步结束", "跳转到" + stepSetInfo.StepList[currNum].StepName + "工步");
                                queJump.Enqueue(jumpReason);
                            }
                            circDic[index] = 0;
                            stepNum = currNum + 1;
                            CommandData(stepNum - 1);
                        }
                    }
                    break;
                case "搁置":
                    {
                        currentState = "搁置";
                        //如果搁置工步的前一工步不为搁置工步，则需下发暂停指令。
                        //如果前一工步也为搁置工步，无需再下发指令
                        if (preStepType != 9)
                        {
                            if (!runState.isParalle)
                            {
                                //搁置指令下达
                                inAction.stepNum = index;
                                inAction = StepRunControl.IndependentStop(inAction, temp, client);
                            }
                            else
                            {
                                //搁置指令下达
                                paAction.stepNum = index;
                                paAction = StepRunControl.ParalleStop(paAction, temp, client);
                            }
                        }
                        preStepType = 9;
                        beginTime = System.DateTime.Now;
                    }
                    break;
                case "暂停":
                    {
                        currentState = "暂停";
                        if (!runState.isParalle)
                        {
                            //搁置指令下达
                            inAction.stepNum = index;
                            inAction = StepRunControl.IndependentStop(inAction, temp, client);
                        }
                        else
                        {
                            //搁置指令下达
                            paAction.stepNum = index;
                            paAction = StepRunControl.ParalleStop(paAction, temp, client);
                        }
                        preStepType = 9;
                        beginTime = System.DateTime.Now;
                    }
                    break;
                case "结束":
                    {
                        currentState = "结束";
                        Closing();
                    }
                    break;
                default:
                    {
                        //通过CustomStep类拆分工步名称，得到其通道模式，通道波形等信息
                        CustomStep customStep = new CustomStep();
                        customStep = customStep.Spilt(stepName, stepSetInfo.StepList[index].Mode);
                        //独立模式工步切换
                        if (!runState.isParalle)
                        {
                            //设置独立参数包的工步类型和保护条件参数
                            inPara = StepRunControl.SetIndeStepParam(inPara, customStep, index, stepSetInfo);
                            //设置独立参数包的通道指令参数
                            inPara = StepRunControl.SetIndeParam(inPara, customStep, index, stepSetInfo);
                            //如果为第一工步，则直接下发参数包
                            if (preStepType == 0)
                            {
                                temp = inPara.Command();

                                StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));
                            }
                            //如果不为第一工步且与前一工步相同类型，则需考虑两种情况
                            //1.若都为工况工步，则需暂停，暂停撤回，下参数，启动，启动撤回
                            //2.若都为普通工步，则只需下参数
                            else if (customStep.Type == preStepType)
                            {
                                //如果当前为工况工步
                                if (customStep.Type >= 10 && customStep.Type <= 13)
                                {
                                    //下发暂停指令
                                    inAction.stepNum = index;
                                    inAction = StepRunControl.IndependentStop(inAction, temp, client);
                                    //Thread.Sleep(10);
                                    SwitchToIndeCondition(index, stepName, customStep);
                                }
                                else
                                {
                                    temp = inPara.Command();

                                    StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                                    beginTime = System.DateTime.Now;
                                }
                            }
                            //如果与上一工步为不同类型工步且上一工步不是搁置工步
                            else if (preStepType != 9)
                            {
                                //若当前为工况工步，则需暂停，暂停撤回，下参数，启动，启动撤回
                                if (customStep.Type >= 10 && customStep.Type <= 13)
                                {
                                    //下发暂停指令
                                    inAction.stepNum = index;
                                    inAction = StepRunControl.IndependentStop(inAction, temp, client);
                                    //Thread.Sleep(10);
                                    SwitchToIndeCondition(index, stepName, customStep);
                                }
                                //若当前为普通工步，则需暂停，下参数，启动，启动撤回
                                else
                                {
                                    //下发暂停指令
                                    inAction.stepNum = index;
                                    inAction = StepRunControl.IndependentStop(inAction, temp, client);
                                    //Thread.Sleep(10);
                                    //下发下一工步参数指令
                                    temp = inPara.Command();

                                    StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                                    //Thread.Sleep(10);                                    
                                    //下发启动指令                              
                                    inAction = StepRunControl.IndependentStart(inAction, temp, client);
                                    beginTime = System.DateTime.Now;
                                    //Thread.Sleep(10);
                                    //下发启动撤回指令
                                    inAction = StepRunControl.IndependentStartBack(inAction, temp, client);
                                }
                            }
                            //上一工步为搁置工步
                            else
                            {
                                //若当前为工况工步，则需暂停撤回，下参数，启动，启动撤回
                                if (customStep.Type >= 10 && customStep.Type <= 13)
                                {
                                    SwitchToIndeCondition(index, stepName, customStep);
                                }
                                //若当前为普通工步，则需下参数，启动，启动撤回
                                else
                                {
                                    //下发下一工步参数指令
                                    temp = inPara.Command();

                                    StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                                    //Thread.Sleep(10);
                                    //下发启动指令                              
                                    inAction = StepRunControl.IndependentStart(inAction, temp, client);
                                    beginTime = System.DateTime.Now;
                                    //Thread.Sleep(10);
                                    //下发启动撤回指令
                                    inAction = StepRunControl.IndependentStartBack(inAction, temp, client);
                                }
                            }
                        }
                        //并联模式工步切换
                        else
                        {
                            //设置独立参数包的工步类型和保护条件参数
                            paPara = StepRunControl.SetParaStepParam(paPara, customStep, index, stepSetInfo);
                            //设置独立参数包的通道指令参数
                            paPara = StepRunControl.SetParaParam(paPara, customStep, index, stepSetInfo);
                            //如果为第一工步，则直接下发参数包
                            if (preStepType == 0)
                            {
                                temp = paPara.Command();

                                StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                            }
                            //如果不为第一工步且与前一工步相同类型，则需考虑两种情况
                            //1.若都为工况工步，则需暂停，暂停撤回，下参数，启动，启动撤回
                            //2.若都为普通工步，则只需下参数
                            else if (customStep.Type == preStepType)
                            {
                                //如果当前为工况工步
                                if (customStep.Type >= 10 && customStep.Type <= 13)
                                {
                                    //下发暂停指令
                                    paAction.stepNum = index;
                                    paAction = StepRunControl.ParalleStop(paAction, temp, client);
                                    //Thread.Sleep(10);
                                    SwitchToParaCondition(index, stepName, customStep);
                                }
                                else
                                {
                                    temp = paPara.Command();

                                    StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                                    beginTime = System.DateTime.Now;
                                }
                            }
                            //如果与上一工步为不同类型工步且上一工步不是搁置工步
                            else if (preStepType != 9)
                            {
                                //若当前为工况工步，则需暂停，暂停撤回，下参数，启动，启动撤回
                                if (customStep.Type >= 10 && customStep.Type <= 13)
                                {
                                    //下发暂停指令
                                    paAction.stepNum = index;
                                    paAction = StepRunControl.ParalleStop(paAction, temp, client);
                                    //Thread.Sleep(10);
                                    SwitchToParaCondition(index, stepName, customStep);
                                }
                                //若当前为普通工步，则需暂停，下参数，启动，启动撤回
                                else
                                {
                                    //下发暂停指令
                                    paAction.stepNum = index;
                                    paAction = StepRunControl.ParalleStop(paAction, temp, client);
                                    //Thread.Sleep(10);
                                    //下发下一工步参数指令
                                    temp = paPara.Command();

                                    StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                                    //Thread.Sleep(10);                                    
                                    //下发启动指令                              
                                    paAction = StepRunControl.ParalleStart(paAction, temp, client);
                                    beginTime = System.DateTime.Now;
                                    //Thread.Sleep(10);
                                    //下发启动撤回指令
                                    paAction = StepRunControl.ParalleStartBack(paAction, temp, client);
                                }
                            }
                            //上一工步为搁置工步
                            else
                            {
                                //若当前为工况工步，则需暂停撤回，下参数，启动，启动撤回
                                if (customStep.Type >= 10 && customStep.Type <= 13)
                                {
                                    SwitchToParaCondition(index, stepName, customStep);
                                }
                                //若当前为普通工步，则需下参数，启动，启动撤回
                                else
                                {
                                    //下发下一工步参数指令
                                    temp = paPara.Command();

                                    StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

                                    //Thread.Sleep(10);
                                    //下发启动指令                              
                                    paAction = StepRunControl.ParalleStart(paAction, temp, client);
                                    beginTime = System.DateTime.Now;
                                    //Thread.Sleep(10);
                                    //下发启动撤回指令
                                    paAction = StepRunControl.ParalleStartBack(paAction, temp, client);
                                }
                            }
                        }
                        if ((stepName != "斜坡工况" && stepName != "脉冲工况") || (preStepType == 0))
                        {
                            //更新工步类型
                            preStepType = customStep.Type;
                            currentState = stepName;
                        }
                    }
                    break;
            }
            runState.isChanged = true;
        }
        /// <summary>
        /// 独立模式切换到工况工步
        /// </summary>
        /// <param name="index"></param>
        /// <param name="stepName"></param>
        /// <param name="customStep"></param>
        private void SwitchToIndeCondition(int index, string stepName, CustomStep customStep)
        {
            //暂停撤回
            inAction = StepRunControl.IndependentStopBack(inAction, temp, client);
            //Thread.Sleep(10);
            //下发下一工步参数指令
            temp = inPara.Command();

            StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

            //Thread.Sleep(10);
            //更新通道状态
            preStepType = customStep.Type;
            currentState = stepName;
            runState.isChanged = true;
            //更新工况数据
            dt = stepSetInfo.StepList[index].Dt;
            runState.hasMoreData = true;
            IndependSendWork(dt, inCondition);//发送前两条工况指令
            //收到工况请求
            if (runState.receiveConReq)
            {
                runState.receiveConReq = false;
                //Thread.Sleep(10);
                //下发启动指令                              
                inAction = StepRunControl.IndependentStart(inAction, temp, client);
                beginTime = System.DateTime.Now;
                //Thread.Sleep(10);
                //下发启动撤回指令
                inAction = StepRunControl.IndependentStartBack(inAction, temp, client);
                //发送剩下的工况数据
                SendConditionOverJudge();
                if (runState.isConditionIfJump)
                {
                    runState.isConditionIfJump = false;
                }
                else
                {
                    beginTime = default(DateTime);
                    if (runState.isConditionTimeOut)
                    {
                        runState.isConditionTimeOut = false;
                    }
                    else
                    {
                        if (RecordJump == "1")
                        {
                            string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                            JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "工况工步数据处理完毕", "跳转到" + stepSetInfo.StepList[index + 1].StepName + "工步");
                            queJump.Enqueue(jumpReason);
                        }
                    }
                    stepNum = index + 2;
                    CommandData(stepNum - 1);
                }
            }
        }
        /// <summary>
        /// 并联模式切换到工况工步
        /// </summary>
        /// <param name="index"></param>
        /// <param name="stepName"></param>
        /// <param name="customStep"></param>
        private void SwitchToParaCondition(int index, string stepName, CustomStep customStep)
        {
            //暂停撤回
            paAction = StepRunControl.ParalleStopBack(paAction, temp, client);
            //Thread.Sleep(10);
            //下发下一工步参数指令
            temp = paPara.Command();

            StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

            //Thread.Sleep(10);
            //更新通道状态
            preStepType = customStep.Type;
            currentState = stepName;
            runState.isChanged = true;
            //更新工况数据
            dt = stepSetInfo.StepList[index].Dt;
            runState.hasMoreData = true;
            ParalleSendWork(dt, paCondition);//发送前两条工况指令
            if (runState.receiveConReq)
            {
                runState.receiveConReq = false;
                //Thread.Sleep(10);
                //下发启动指令                              
                paAction = StepRunControl.ParalleStart(paAction, temp, client);
                beginTime = System.DateTime.Now;
                //Thread.Sleep(10);
                //下发启动撤回指令
                paAction = StepRunControl.ParalleStartBack(paAction, temp, client);
                //发送剩下的工况数据
                SendConditionOverJudge();
                if (runState.isConditionIfJump)
                {
                    runState.isConditionIfJump = false;
                }
                else
                {
                    beginTime = default(DateTime);
                    if (runState.isConditionTimeOut)
                    {
                        runState.isConditionTimeOut = false;
                    }
                    else
                    {
                        if (RecordJump == "1")
                        {
                            string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                            JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "工况工步数据处理完毕", "跳转到" + stepSetInfo.StepList[index + 1].StepName + "工步");
                            queJump.Enqueue(jumpReason);
                        }
                    }
                    stepNum = index + 2;
                    CommandData(stepNum - 1);
                }
            }
        }
        #endregion
        #region 工况请求处理和工况数据下发
        /// <summary>
        /// 工况请求校验中
        /// </summary>
        private void ReceiveReqStateJudge(float waitTime)
        {
            //判断是否在等待工况请求中
            runState.isReceiveJudge = true;
            timerRecReq = new System.Timers.Timer(waitTime);
            timerRecReq.Elapsed += (s, ela) =>
            {
                //如果在开机后没有收到工况请求，则关机
                if (stepNum != stepSetInfo.StartStep)
                {
                    runState.isOn = false;
                    currentState = "结束";
                    Closing();
                    if (RecordJump == "1")
                    {
                        string circStr = StepRunControl.MakeCircStr(circDic, circList, stepSetInfo);
                        JumpReasonRecord jumpReason = new JumpReasonRecord(stepSetInfo.TestId, stepSetInfo.DevIp, stepSetInfo.Gid, stepSetInfo.Mid, stepSetInfo.Cid,
                                stepNum, circStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "未收到工况请求", "跳转到完成状态");
                        queJump.Enqueue(jumpReason);
                    }
                    ThreadPool.QueueUserWorkItem(new WaitCallback(StepRunControl.CondiShowMsg), stepSetInfo);
                }
                //如果在开机前没有收到工况请求，则提示用户开机失败
                else
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(StepRunControl.CondiShowMsg), stepSetInfo);
                }
                runState.isReceiveJudge = false;
                timerRecReq.Close();
            };
            timerRecReq.AutoReset = false;
            timerRecReq.Enabled = true;
            timerRecReq.Start();
        }
        /// <summary>
        /// 工况数据没发送完前循环接收请求
        /// </summary>
        private void SendConditionOverJudge()
        {
            if (runState.hasMoreData)
            {
                float waitTime = TotalTimeControl.CalTotalTime(count, dt, "时间") * 1000 + 5000;
                //等待工况请求
                ReceiveReqStateJudge(waitTime);
            }
            //上位机判断包发完没有，中位机判断包发完没有；cs 收到数据，后面的尾包标志，
            while (runState.hasMoreData || !cs.DCoff_LastPackEnd)
            {
                //如果工况执行时间达到
                if (runState.isConditionTimeOut || runState.isConditionIfJump)
                {
                    count = 0;
                    break;
                }
                continue;
            }
            if (!runState.hasMoreData)
            {
                count = 0;
            }
        }
        /// <summary>
        /// 并联工况发送第一笔数据
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public CommandProtocol.ParalleWorkCondition ParalleSendWork(DataTable dt, CommandProtocol.ParalleWorkCondition paCondition)
        {
            int chaNum;
            if (dt.Rows.Count <= 30 * (count + 1))//即将下发的数据不足30 条了
            {
                chaNum = dt.Rows.Count - 30 * count;
                runState.hasMoreData = false;
                paCondition.isLast = true;
                paCondition.lastNum = chaNum;
            }
            else
            {
                chaNum = 30;
                paCondition.isLast = false;
                paCondition.lastNum = 0;
            }
            int paraCount = stepSetInfo.ParallelList.Count;
            //准备工况数据
            paCondition = StepRunControl.PreParalleConditionData(chaNum, dt, count, paCondition, paraCount);
            count++;
            //发送第一笔数据
            temp = paCondition.Command();

            StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

            //Thread.Sleep(10);
            float waitTime = 5000;
            ReceiveReqStateJudge(waitTime);//开始等待工况请求
            while (runState.isReceiveJudge)
            {
                continue;
            }
            return paCondition;
        }
        /// <summary>
        /// 独立工况发送第一笔数据
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="inCondition"></param>
        /// <returns></returns>
        public CommandProtocol.IndependWorkCondition IndependSendWork(DataTable dt, CommandProtocol.IndependWorkCondition inCondition)
        {
            int chaNum;
            if (dt.Rows.Count <= 30 * (count + 1))//即将下发的数据不足30 条了
            {
                chaNum = dt.Rows.Count - 30 * count;
                runState.hasMoreData = false;
                inCondition.isLast = true;
                inCondition.lastNum = chaNum;
            }
            else
            {
                chaNum = 30;
                inCondition.isLast = false;
                inCondition.lastNum = 0;
            }
            //准备工况数据
            inCondition = StepRunControl.PreIndependConditionData(chaNum, dt, count, inCondition);
            count++;
            //发送第一笔数据
            temp = inCondition.Command();

            StartListen.queSendDic[stepSetInfo.DevIp].Enqueue(new SendInfo(temp, client));

            //Thread.Sleep(10);
            float waitTime = 5000;
            ReceiveReqStateJudge(waitTime);//开始等待工况请求
            while (runState.isReceiveJudge)
            {
                continue;
            }
            return inCondition;
        }
        #endregion
    }
}
